package com.wlz.file;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Random;

/**
 * @author wlz
 * @date 2022-10-28  10:21 上午
 */
@Slf4j
public class FileCopyTest {

    public static void main(String[] args) throws IOException {
        String fullPath = "/Users/wlz/Desktop/HUMTEST_30-40.zip";
//        copyStream(fullPath);
//        copyChannel(fullPath);
//        copyChannel2(fullPath);
//        hutOOLCopyIOUtil(fullPath);
//        huToolCopy(fullPath);
        copyMemory(fullPath);
    }

    public static void copyMemory(String fullPath) throws IOException {
        long time = System.currentTimeMillis();
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        copyFileByMemoryMap(fullPath, destPackagePath + fullPath.substring(fullPath.lastIndexOf("/")));
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }

    public static void copyStreamBuffer(String fullPath) throws IOException {
        long time = System.currentTimeMillis();
        File originalPackageFile = new File(fullPath);
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        File destPackageFile = new File(destPackagePath, fullPath.substring(fullPath.lastIndexOf("/")));
        copyFileBuffered(originalPackageFile, destPackageFile);
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }


    public static void hutOOLCopyIOUtil(String fullPath) throws IOException {
        long time = System.currentTimeMillis();
        FileInputStream inputStream= new  FileInputStream(new File(fullPath));
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        FileOutputStream outputStream = new FileOutputStream(destPackagePath + fullPath.substring(fullPath.lastIndexOf("/")));
        IoUtil.copy(inputStream,outputStream);
        IoUtil.close(outputStream);
        IoUtil.close(inputStream);
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }


    private static void huToolCopy(String fullPath) {
        long time = System.currentTimeMillis();
        File originalPackageFile = new File(fullPath);
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        File copy;
        try {
            copy = FileUtil.copy(originalPackageFile, destFilePath, true);
        } catch (IORuntimeException e) {
            e.printStackTrace();
        }
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }


    public static void copyChannel(String fullPath) throws IOException {
        long time = System.currentTimeMillis();
        File originalPackageFile = new File(fullPath);
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        File destPackageFile = new File(destPackagePath, fullPath.substring(fullPath.lastIndexOf("/")));

        copyFileUsingFileStreams(originalPackageFile, destPackageFile);
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }

    public static void copyChannel2(String fullPath) throws IOException {
        long time = System.currentTimeMillis();
        File originalPackageFile = new File(fullPath);
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        File destPackageFile = new File(destPackagePath, fullPath.substring(fullPath.lastIndexOf("/")));

        copyFileUsingFileStreams2(originalPackageFile, destPackageFile);
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }

    public static void copyStream(String fullPath) throws IOException{
        long time = System.currentTimeMillis();
        String destPackagePath = fullPath.substring(0, fullPath.lastIndexOf("."));
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        copyFileUsingFileStream(new File(fullPath), new File(destPackagePath + fullPath.substring(fullPath.lastIndexOf("/"))));
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }

    public static void copy3() throws IOException {
        long time = System.currentTimeMillis();
        String destPackagePath = "/Users/wlz/Desktop/test/HUMTEST221027/";
        File destFilePath = new File(destPackagePath);
        if (!destFilePath.exists()) {
            destFilePath.mkdirs();
        }
        copy4("/Users/wlz/Desktop/test/HUMTEST221027.zip", destPackagePath + "HUMTEST221028.zip");
        System.out.println("time : " + (System.currentTimeMillis() - time));
    }

    public static void copy4(String source, String original) throws IOException {
        //准备输入流(源文件)
        FileInputStream fileInputStream = new FileInputStream(source);
        //准备输出流(目标文件)
        FileOutputStream fileOutputStream = new FileOutputStream(original);

        //根据流获取通道
        FileChannel inputStreamChannel = fileInputStream.getChannel();
        FileChannel outputStreamChannel = fileOutputStream.getChannel();

        //指向复制方法
//        outputStreamChannel.transferFrom(inputStreamChannel,0,inputStreamChannel.size());
        inputStreamChannel.transferTo(0,inputStreamChannel.size(),outputStreamChannel);

        //关闭资源
        fileInputStream.close();
        fileOutputStream.close();
    }


    public static void copyFileUsingFileStreams(File source, File dest) throws IOException {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            inputChannel = new FileInputStream(source).getChannel();
            outputChannel = new FileOutputStream(dest).getChannel();
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
        } finally {
            for (FileChannel fileChannel : Arrays.asList(inputChannel, outputChannel)) {
                fileChannel.close();
            }
        }
    }


    public static void copyFileUsingFileStreams2(File source, File dest) throws IOException {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            inputChannel = new FileInputStream(source).getChannel();
            outputChannel = new FileOutputStream(dest).getChannel();
            long size = inputChannel.size();
            for (long left = size; left > 0;) {
                System.out.println( String.format("position: 【%s】,left: 【%s】",  size - left, left));
                left -= inputChannel.transferTo((size - left), left, outputChannel);
            }
        } finally {
            for (FileChannel fileChannel : Arrays.asList(inputChannel, outputChannel)) {
                fileChannel.close();
            }
        }
    }

    /**
     *   文件复制
     * @param source 文件
     * @param original 文件
     */
    public static void copyFileUsingFileStream(File source, File original) throws IOException{
        long start = System.currentTimeMillis();
        FileInputStream input = null;
        FileOutputStream output = null;
        try {
            input = new FileInputStream(source);
            output = new FileOutputStream(original);
            byte[] buffer = new byte[1024*1024];
            int len = 0;
            while((len = input.read(buffer)) != -1) {
                output.write(buffer);
            }
        }finally {
            if(input != null) {
                input.close();
            }
            if(output != null) {
                output.close();
            }
        }
        log.info("文件复制 文件名为 {},  耗时: {} ms ", source.getAbsoluteFile(), System.currentTimeMillis() - start);
    }


    public static void copyFileBuffered(File source, File original) throws IOException{
        long start = System.currentTimeMillis();
        FileInputStream input = null;
        FileOutputStream output = null;
        BufferedInputStream bufR = null;
        BufferedOutputStream bufW = null;
        try {
            input = new FileInputStream(source);
            output = new FileOutputStream(original);
            bufR = new BufferedInputStream(input);
            bufW = new BufferedOutputStream(output);
            int temp = 0;
            while ((temp = bufR.read()) != -1) {
                bufW.write(temp);
            }
        }finally {
            if (bufR != null) {
                input.close();
                bufR.close();
            }
            if (bufW != null) {
                output.close();
                bufW.close();
            }
        }
        log.info("文件复制 文件名为 {},  耗时: {} ms ", source.getAbsoluteFile(), System.currentTimeMillis() - start);
    }

    public static void copyFileByMemoryMap(String source, String target) {
        try(FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(target)) {
            FileChannel sourceChannel = fis.getChannel();
            FileChannel targetChannel = fos.getChannel();
            //512m
            long length = 1L << 29;
            //4g
            long size = sourceChannel.size();
            long cur = 0L;
            MappedByteBuffer mappedByteBuffer;
            while (cur < size) {
                mappedByteBuffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, cur, length);
                targetChannel.write(mappedByteBuffer);
                cur += length;

            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
